﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Collections;

namespace KeyboardImageViewer
{
    public static class MatrixOperations
    {
        private static double[,] featureMatrix;
        private static double[] meansVector;

        public static double[,] FeatureMatrix
        {
            get
            {
                if (featureMatrix == null)
                {
                    featureMatrix = new double[DuplicateUtils.HashLength, DuplicateUtils.FeatureLength];

                    Assembly assembly = Assembly.GetExecutingAssembly();
                    string[] resourceNames = assembly.GetManifestResourceNames();

                    // Load feature matrix from file
                    using (StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("KeyboardImageViewer.Duplicates.featureMatrix.txt")))
                    {
                        string line;
                        int row = 0;

                        while (!string.IsNullOrEmpty(line = reader.ReadLine()))
                        {
                            string[] rowParts = line.Split(',');

                            for (int col = 0; col < DuplicateUtils.FeatureLength; col++)
                            {
                                featureMatrix[row, col] = double.Parse(rowParts[col]);
                            }

                            row++;
                        }
                    }
                }

                return featureMatrix;
            }
        }

        public static double[] MeansVector
        {
            get
            {
                if (meansVector == null)
                {
                    meansVector = new double[DuplicateUtils.HashLength];

                    // Load means vector from file
                    using (StreamReader reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("KeyboardImageViewer.Duplicates.meansVector.txt")))
                    {
                        string line = reader.ReadLine();

                        string[] vectorParts = line.Split(',');

                        for (int i = 0; i < DuplicateUtils.HashLength; i++)
                        {
                            meansVector[i] = double.Parse(vectorParts[i]);
                        }
                    }
                }

                return meansVector;
            }
        }

        public static byte[] CalculateHash(byte[] featureVector)
        {
            double[] gVector = Multiply(FeatureMatrix, featureVector);

            BitArray workingHash = new BitArray(DuplicateUtils.HashLength);

            for (int i = 0; i < DuplicateUtils.HashLength; i++)
            {
                if (gVector[i] > MeansVector[i])
                {
                    workingHash[i] = true;
                }
                else
                {
                    workingHash[i] = false;
                }
            }

            byte[] resultHash = new byte[DuplicateUtils.HashLength / 8];
            workingHash.CopyTo(resultHash, 0);

            return resultHash;
        }

        private static double[] Multiply(double[,] matrix, byte[] vector)
        {
            int rows = matrix.GetLength(0);
            int columns = matrix.GetLength(1);

            if (columns != vector.Length)
            {
                throw new ArgumentException("Matrix width must equal vector length.");
            }

            double[] resultVector = new double[rows];

            for (int row = 0; row < rows; row++)
            {
                for (int i = 0; i < vector.Length; i++)
                {
                    resultVector[row] += matrix[row, i] * vector[i];
                }
            }

            return resultVector;
        }
    }
}
